在這系列教學裡,我們以撰寫一個以購物車為主題的 Kotlin 函式庫為例,經過一連串 TDD、語法風格查、靜態分析、Build Scan、覆蓋率報告、API 文件等流程,我們已經確保了我們的程式碼品質,是時候把它發佈出去讓使用者使用了!
以 JVM 生態系來說,大部份的開發者會把套件發佈在 Maven Central、JCenter、Bintray 上。不過 JFrog 在今年 2 月宣佈從 5 月 1 日起關閉 JCenter 及 Bintray 等服務,引發一批搬家潮;而 Maven Central 則是在發佈上出了名的難設定,當初筆者剛轉入 JVM 生態系時也被發佈套件的難度給驚嚇到。難道沒有什麼簡單上手、又方便跟 TeamCity 結合的發佈平台嗎?
JetBrains 在 2019 年的 KotlinConf 活動上發佈了全新的 Space 平台 ,這是一個包含了 VCS Hosting、Project Management、Team Directory、Blog、Chat、CI/CD 等軟體開發團隊一定會用到的多合一工具平台。其中的 Project 與 VCS Hosting 功能裡,就附帶了 Maven Repository 的功能,讓 JVM 生態系的開發者可以很方便的以 JetBrains Space 做為套件發佈的平台!
在今天的練習裡,我們將結合 Space 及 TeamCity 並將 ShoppingCart 這個購物車套件發佈出去。在跟著練習之前,請先到 Space 官方網站 以註冊一個團隊空間來使用,註冊帳號和開 Project 都是免費的。
首先我們要在 Space 上設定一個 Project,請先點選畫面上左下角的「+」按鈕,選擇新增一個 Project。
在彈出來的視窗裡,Name 取名為 ShoppingCart Library、Key 設定為 SCL(皆可依需求自行調整),完成後按 Create 建立 Project。
接著會進到 Project 首頁,點選左邊側邊欄的 Packages 選項,再按下畫面中間的 New repository。
在隨後的彈出視窗裡,Type 選擇 Maven Repository、Name 取名為 space(可依需求自行調整)完成後按 Create 建立 Package Repository。
完成後會跳轉到 Package Repository 首頁,點一下畫面上的 Get started,會有一個彈出式視窗告訴我們怎麼設定,在 Tool 的部份選擇 Gradle (Kotlin),下方就會出現對應的 Gradle 設定檔,讓我們只需要複製貼上即可。
依照畫面上的說明,第一件事就是要安裝 Maven Publish 這個 Gradle Plugin:
plugins {
// ...
`maven-publish`
}
因為名稱的關係,要注意這個 Plugin 名字必需用 Backtick 符號夾起來,新增後記得要在 IntelliJ IDEA 裡 Reload 一次 Gradle,完成後應該會看到 Gradle 面板裡多了一個 publishing
的群組。
接著要設定 Gradle 的 Publish 動作以及連上 JetBrains Space 的連線資訊:
val spaceUsername: String? by project
val spacePassword: String? by project
version = System.getenv("PACKAGE_VERSION") ?: "1.0-SNAPSHOT"
publishing {
publications {
create<MavenPublication>("main") {
groupId = project.group.toString()
artifactId = project.name
version = project.version.toString()
from(components["java"])
}
}
repositories {
maven {
name = "space"
url = uri("...")
credentials {
username = spaceUsername ?: System.getenv("SPACE_USERNAME")
password = spacePassword ?: System.getenv("SPACE_PASSWORD")
}
}
}
}
以上範例程式碼跟 Space 上提供的有些不同,主要的原因是我們想從 CI 直接以環境變數的方式把設定值寫入,而不是寫死在設定檔裡。因此要修改的地方包括:spaceUsername
及 spacePassword
的型別改用 String?
。version
版本號會從環境變數抓,假如沒有的話會以 1.0-SNAPSHOT
做預設值。publications
底下的 groupId
、artifactId
、version
都改成從 project
抓取資訊。credentials
底下的 username
及 password
都先抓 Gradle Properties,不然就是從環境變數抓。最後,在 maven
底下加上 name
的設定,方便我們識別 Gradle 的任務名稱。完成後別忘了再 Reload 一次 Gradle,這次 Reload 完成後,會看到 publishing
群組裡多了很多任務可以使用。
為了方便在本機測試,我們先在 gradle.properties
裡新增 spaceUsername
及 spacePassword
兩個參數,從剛剛的彈出式視窗裡點選 Generate personal token 後,直接複製貼上視窗裡產生出來的 token 資料。接著回到 IntelliJ IDEA 裡的 Gradle 面板,直接點選 publish
任務執行,待 Gradle 完成所有動作後,Package 就成功的發佈到 JetBrains Space 上了。
接下來我們要仿照之前發佈 API 文件的方式,以新增一個 Build Configuration 的方式來發佈 Package。建立 Build Configuration 的流程可以參考前面幾天的教學,今天要設定的 Build Step 的 Runner type 一樣是 Gradle,但是 Task 指令用的是 publish
,設定完成後按 Save 儲存。
設定好 Build Configuration 後,TeamCity 就可以幫我們一鍵把 Package 發佈出去。但是別忘了在發佈 Package 的時候,需要使用 Space 的 Personal token 才能將 Artifact 送上去,可是我們又不希望把 Personal token 這種機敏資訊寫在 gradle.properties
並曝露在 VCS 裡。這時我們可以用 TeamCity 的環境變數來動態地把 token 傳給 Runner 執行。
首先進到 Publish artifact 設定,點選左邊側邊欄的 Parameters,進到參數設定頁。
點選上方 Add new parameter 按鈕,在彈出式視窗裡,Name 輸入 SPACE_USERNAME
、Kind 選擇 Environment variable (env.)、Value 輸入從 Space 取得的 Personal token 的帳號,完成後按 Save 儲存。
以同樣的方式再完成 SPACE_PASSWORD
的設定。
別忘了我們在 Gradle Build Script 裡還有 PACKAGE_VERSION
也需要設定環境變數。但跟 SPACE_USERNAME
及 SPACE_PASSWORD
不一樣的地方是,PACKAGE_VERSION
在每次執行的時候值都應該要不一樣(因為要發佈成不同的版本號),所以我們不要用專案的環境變數寫死,而是在每次執行的時候才輸入。所以當我們在發佈 Package 的時候,不要直接按 Build Configuration 旁的 Run 按鈕,而是要按下 Run 按鈕旁的「...」按鈕。
在彈出式視窗裡,選擇 Parameters 頁籤,選擇類型為 Environment variable。名稱輸入 PACKAGE_VERSION
、值輸入想要產生的版本號,按下右邊的 add 完成新增,最後再按下 Run Build 執行建置並發佈。
今天我們體驗了 JetBrains Space 平台的 Maven Repository 功能,同時也整合了 TeamCity 的環境變數、自動化發佈的流程,讓 JVM 開發者更方便的完成套件發佈與儲存的功能。希望這篇教學可以幫助到跟我一樣卡在發佈流程的苦主,若是對 Space 進階功能有更多的興趣,可以參考一下官方 售價表 了解細節。